package algorithm.dp;

public class 不同的子序列N {
    /*
     * 给定一个字符串 S 和一个字符串 T，计算在 S 的子序列中 T 出现的个数。
     * 
     * 一个字符串的一个子序列是指，通过删除一些（也可以不删除）字符且不干扰剩余字符相对位置所组成的新字符串。（例如，"ACE" 是 "ABCDE" 
     * 的一个子序列，而 "AEC" 不是）
     * 示例1
                输入: S = "rabbbit", T = "rabbit"
                输出: 3
                解释:
                
                如下图所示, 有 3 种可以从 S 中得到 "rabbit" 的方案。
                (上箭头符号 ^ 表示选取的字母)
                
                rabbbit
                ^^^^ ^^
                rabbbit
                ^^ ^^^^
                rabbbit
                ^^^ ^^^
                示例 2:
                
                输入: S = "babgbag", T = "bag"
                输出: 5
                解释:
                
                如下图所示, 有 5 种可以从 S 中得到 "bag" 的方案。 
                (上箭头符号 ^ 表示选取的字母)
                
                babgbag
                ^^ ^
                babgbag
                ^^    ^
                babgbag
                ^    ^^
                babgbag
                  ^  ^^
                babgbag
                    ^^^

     * 来源：力扣（LeetCode） 链接：https://leetcode-cn.com/problems/distinct-subsequences
     * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
     * 
     */
    public int numDistinct(String s, String t) {
        /*
         * s[0:i-1]中子序列t[0:j-1]个数为n,如果s[i]=t[j],那么s[0:i]中子序列t[0:j]的个数也为n,如果s
         * [i]=t[j-1],那么s[0:i]中序列t[0:j-1]的数量为2n(只是加了底数的一倍，不是乘2)
         */
        int lens = s.length();
        int lent = t.length();
        if (lent > lens || lens == 0) {
            return 0;
        }
        int[][] dp = new int[lens + 5][lent + 5];// dim=0 底数，dim=1 倍数
        dp[0][0] = 0;

        for (int i = 0; i < lens; i++) {
            for (int j = 0; j < lent; j++) {
                if (s.charAt(i) == t.charAt(j)) {
                    dp[i + 1][j + 1] += dp[i][j];
                    dp[i + 1][j + 1] += dp[i][j + 1];
                    if (dp[i + 1][j + 1] == 0) {
                        dp[i + 1][j + 1] = 1;
                    }
                } else {
                    dp[i + 1][j + 1] = dp[i][j + 1];
                }

            }
        }
        return dp[lens][lent];
    }

    public static void main(String[] args) {
        不同的子序列N run = new 不同的子序列N();
        System.out.println(run.numDistinct("babgbag", "bag"));
    }
}
